#include "FreeRTOS.h"

#include "cfg.h"
#include "cmsis_os.h"
#include "gpio.h"
#include "lwip.h"
#include "lwip/inet.h"
#include "lwip/init.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/sockets.h"
#include "main.h"
#include "spi.h"
#include "stdio.h"
#include "string.h"
#include "task.h"
#include "tcp_com.h"
#include "usart.h"

uint32_t ethernet_read_phy(uint16_t reg) {
    uint32_t regval;
    HAL_ETH_ReadPHYRegister(&heth, reg, &regval);
    return regval;
}

void ethernet_write_phy(uint16_t reg, uint16_t value) {
    uint32_t temp = value;
    HAL_ETH_WritePHYRegister(&heth, reg, temp);
}

void phy_write_extphyreg(uint16_t a, uint16_t b) {
    ethernet_write_phy(0x1e, a);
    ethernet_write_phy(0x1f, b);
}

uint32_t phy_read_extphyreg(uint16_t a) {
    ethernet_write_phy(0x1e, a);
    return ethernet_read_phy(0x1f);
}

osThreadId defaultTaskHandle;
osThreadId tcpCliTaskHandle;
osThreadId tcpSrvTaskHandle;
osThreadId usartTaskHandle;
osTimerId relayTimerHandle;
osTimerId wtdTimerHandle;

static uint32_t pressStartTime = 0;
void wtdTimerCallback(void const *argument) {
    static int first_ = pdTRUE;
    static int run_num = 0;
    if (first_ == pdTRUE) {
        hardware_Watchdog_Init();
        first_ = pdFALSE;
    }
    if (run_num++ > 8) {
        LED1_TOGGLE_PIN;
        Feed_Watchdog();
        run_num = 0;
    }

    // 按键按下（低电平）
    if (HAL_GPIO_ReadPin(RESET_GPIO_PORT, RESET_GPIO_PIN) == GPIO_PIN_RESET) {
        if (pressStartTime == 0) {
            pressStartTime = xTaskGetTickCount();
        }

        if ((xTaskGetTickCount() - pressStartTime) >= pdMS_TO_TICKS(5000)) {
            // printf("Button held for 5 seconds!\n");
            pressStartTime = 0;
        }
    } else {
        pressStartTime = 0;  // 按键松开，重置计时
    }
}

// 定义定时器
osTimerDef(relayTimer, TimerCallback);
osTimerDef(wtdTimer, wtdTimerCallback);

void StartDefaultTask(void const *argument);

extern void MX_LWIP_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize);

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize) {
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
    *ppxIdleTaskStackBuffer = &xIdleStack[0];
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/**
 * @brief  FreeRTOS initialization
 * @param  None
 * @retval None
 */
void MX_FREERTOS_Init(void) {
    osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
    defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
 * @brief  Function implementing the defaultTask thread.
 * @param  argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const *argument) {
    MX_LWIP_Init();

    phy_write_extphyreg(0x4210, 0x0);
    phy_write_extphyreg(0x4008, 0xbf2a);
    phy_write_extphyreg(0x2057, 0x297f);
    phy_write_extphyreg(0x14, 0x1fe);
    phy_write_extphyreg(0x15, 0x1fe);

    taskENTER_CRITICAL();
    osMessageQDef(rxQueue, 1, uint32_t);
    rxQueueHandle = osMessageCreate(osMessageQ(rxQueue), NULL);

    relayTimerHandle =
        osTimerCreate(osTimer(relayTimer), osTimerPeriodic, NULL);
    if (relayTimerHandle == NULL) {
        printf("Timer creation failed!\r\n");
    }

    wtdTimerHandle = osTimerCreate(osTimer(wtdTimer), osTimerPeriodic, NULL);
    if (wtdTimerHandle == NULL) {
        printf("Timer creation failed!\r\n");
    }

    osThreadDef(tcpServerTask, StartTCPServerTask, osPriorityNormal, 0, 400);
    tcpSrvTaskHandle = osThreadCreate(osThread(tcpServerTask), NULL);
    if (tcpSrvTaskHandle == NULL) {
        printf("tcpServerTask creation failed!\n");
    }

    osThreadDef(tcpClientTask, StartTCPClientTask, osPriorityAboveNormal, 0,
                400);
    tcpCliTaskHandle = osThreadCreate(osThread(tcpClientTask), NULL);
    if (tcpCliTaskHandle == NULL) {
        printf("tcpCliTaskHandle creation failed!\n");
    }

    osThreadDef(usartTask, StartUsartTask, osPriorityHigh, 0, 400);
    usartTaskHandle = osThreadCreate(osThread(usartTask), NULL);
    if (usartTaskHandle == NULL) {
        printf("usartTaskHandle creation failed!\n");
    }

    osTimerStart(wtdTimerHandle, 50);

    if (cfg.ctrl_mode == AUTO_MODE) {
        osTimerStart(relayTimerHandle, 1000);
    } else {
        // HAL_GPIO_WritePin(GPIOD, cfg.channel_value, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, 0x1, GPIO_PIN_SET);
    }

    osThreadTerminate(NULL);

    taskEXIT_CRITICAL();
}
